/**
 * 
 */
package ro.dta.idbi.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JToolBar;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

/**
 * Panel containing a table and a tool bar to display only a subset of the
 * results and allow the user to move forward or backward
 * 
 * @author Tudor Dobrila
 * 
 */
public abstract class AbstractTable extends JPanel implements ActionListener {

	private static final long serialVersionUID = -4191172804965309497L;

	/**
	 * Model of the results table
	 */
	protected DefaultTableModel resultModel;

	/**
	 * Total number of rows in the table
	 */
	protected int totalResults = 0;

	/**
	 * Number of results returned
	 */
	protected int resultsCount = 0;

	/**
	 * Offset used when retrieving results
	 */
	protected int currentOffset = 0;

	/**
	 * Number of results displayed to the user at once
	 */
	protected int resultsShown = 10;

	/**
	 * Back button in the results tool bar
	 */
	protected JButton backBtn;

	/**
	 * Next button in the results tool bar
	 */
	protected JButton nextBtn;

	/**
	 * Page label in the results tool bar
	 */
	protected JLabel pageLabel;

	/**
	 * Table holding the results
	 */
	protected JTable resultsTable;

	/**
	 * Tool bar displayed on top of the table
	 */
	protected JToolBar toolBar;

	/**
	 * Count combo box, used to allow the user select the no. of results / page
	 */
	protected JComboBox<Integer> countComboBox;

	/**
	 * Browsable table class constructor
	 */
	public AbstractTable() {
		setLayout(new BorderLayout());

		toolBar = new JToolBar();
		add(toolBar, BorderLayout.NORTH);

		toolBar.setFloatable(false);
		toolBar.setLayout(new FlowLayout(FlowLayout.LEFT));

		backBtn = new JButton(new ImageIcon("./resources/back.png"));
		backBtn.addActionListener(this);
		backBtn.setName("back");
		backBtn.setToolTipText("Previous page of results");
		toolBar.add(backBtn);

		pageLabel = new JLabel();
		toolBar.add(pageLabel);

		nextBtn = new JButton(new ImageIcon("./resources/forward.png"));
		nextBtn.addActionListener(this);
		nextBtn.setName("next");
		nextBtn.setToolTipText("Next page of results");
		toolBar.add(nextBtn);

		toolBar.add(new JLabel("Results per page: "));

		countComboBox = new JComboBox<Integer>(new Integer[] { 10, 25, 50, 100 });
		countComboBox.addItemListener(new ItemListener() {

			@Override
			public void itemStateChanged(ItemEvent e) {
				resultsShown = Integer.parseInt(countComboBox.getSelectedItem().toString());
				resetOffset();
			}
		});
		toolBar.add(countComboBox);

		resultModel = new DefaultTableModel();
		resultsTable = new JTable(resultModel) {

			private static final long serialVersionUID = -4197711664372733257L;

			public Component prepareRenderer(TableCellRenderer renderer, int rowIndex, int vColIndex) {
				Component c = super.prepareRenderer(renderer, rowIndex, vColIndex);
				if (c instanceof JComponent) {
					JComponent jc = (JComponent) c;
					Object value = getValueAt(rowIndex, vColIndex);
					if (value != null) {
						jc.setToolTipText("<html>" + value.toString().replace("\n", "<br>"));
					}
				}
				return c;
			}
		};
		resultsTable.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		add(new JScrollPane(resultsTable), BorderLayout.CENTER);
	}

	/**
	 * Reset the current offset to zero
	 */
	public void resetOffset() {
		currentOffset = 0;
		fillTable();
	}

	/**
	 * Abstract method used to refresh the contents of the table
	 * 
	 */
	public void fillTable() {
		totalResults = getTotalResults();
		resultsCount = getCurrentResults();

		refreshTable();
	}

	/**
	 * Get the total number of results
	 * 
	 * @return Total number of results
	 */
	public abstract int getTotalResults();

	/**
	 * Get the current number of results to display in the table
	 * 
	 * @return Current number of results to display in the table
	 */
	public abstract int getCurrentResults();

	/**
	 * Refresh the contents of the table
	 */
	public void refreshTable() {
		if (resultsCount < 0 || totalResults < 0) {
			return;
		}

		nextBtn.setEnabled(currentOffset + resultsCount < totalResults);
		backBtn.setEnabled(currentOffset != 0);
		int totalPages = (int) Math.ceil(totalResults / (double) resultsShown);
		int crtPage = (int) Math.floor(currentOffset / (double) resultsShown) + 1;
		pageLabel.setText("Page " + crtPage + " / " + totalPages);

		// Reset results table
		resultModel.setRowCount(0);
		resultModel.setRowCount(resultsCount);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		JComponent source = (JComponent) e.getSource();

		if (source.getName().equals("back")) {
			currentOffset = Math.max(0, currentOffset - resultsShown);
			refreshTable();

			if (currentOffset == 0) {
				backBtn.setEnabled(false);
			}

			if (currentOffset + resultsShown > totalResults) {
				nextBtn.setEnabled(true);
			}
		}

		if (source.getName().equals("next")) {
			currentOffset = Math.min(totalResults, currentOffset + resultsShown);
			refreshTable();

			if (currentOffset == totalResults) {
				nextBtn.setEnabled(false);
			}

			if (currentOffset != 0) {
				backBtn.setEnabled(true);
			}
		}
	}

	/**
	 * @return Table holding the results
	 */
	public JTable getResultsTable() {
		return resultsTable;
	}

}
